﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Psm.Container;
using System.Threading.Tasks;
using Psm.Transport;
using System.Threading;
using System.Net.Sockets;
using Psm.Util;
using System.Diagnostics;

namespace UnitTests
{
    [TestClass]
    public class TcpTransportTests
    {
        private TestContext testContextInstance;

        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        [ClassInitialize]
        public static void ClassSetup(TestContext tc)
        {
            Repository.Initialize();
        }


        [TestMethod]
        public void TcpTransportPerformance()
        {
            ManualResetEvent syncEvent = new ManualResetEvent(false);
            ParallelOptions options = new ParallelOptions();
            options.MaxDegreeOfParallelism = 2;
            int messageCount = 10000;
            int messageSize = 8192;
            byte[] sendBytes = new byte[messageSize];
            byte[] receiveBytes = new byte[messageSize];

            Parallel.Invoke(options,
                () =>
                {
                    IServerTransport tcpServer = Repository.GetInstance<IServerTransport>("TCP_TRANSPORT", "TCP_TEST");
                    tcpServer.NewClient += new EventHandler<NewClientEventArgs>(
                                                        (o,e) =>
                                                        {   
                                                            IClientTransport client = e.ClientTransport;
                                                            for(int count=0; count < messageCount; count++)
                                                                client.SendAsync(new ByteBuffer(sendBytes,0,messageSize,messageSize));
                                                        });
                    tcpServer.Start();
                    syncEvent.WaitOne();
                    tcpServer.Stop();
                },
                () =>
                {
                    Stopwatch watch = new Stopwatch();
                    long receivedData = 0;
                    long totalData = (long)messageCount * (long)messageSize;
                    Thread.Sleep(5000);
                    IRemoteTransport client = Repository.GetInstance<IRemoteTransport>("TCP_TRANSPORT_CLIENT", "TCP_TEST");
                    client.Open();
                    watch.Start();
                    Action<IClientTransport> receiveCallback = null;
                    receiveCallback =   (transport) =>
                                        {
                                            ByteBuffer data = transport.EndReceive();
                                            receivedData += (long)data.Length;
                                            if (receivedData >= totalData)
                                            {
                                                watch.Stop();
                                                //client.Close();
                                                syncEvent.Set();
                                            }
                                            else
                                            {
                                                client.BeginReceive(new ByteBuffer(receiveBytes, 0, 0, messageSize), new Action<IClientTransport>(receiveCallback));
                                            }
                                        };

                    client.BeginReceive(new ByteBuffer(receiveBytes, 0, 0, messageSize), new Action<IClientTransport>(receiveCallback));
                    syncEvent.WaitOne();
                    this.TestContext.WriteLine("{0:n} bytes in {1}ms", totalData, watch.ElapsedMilliseconds);
                    this.TestContext.WriteLine("Throughput is {0}MB", ((double)totalData/(double)watch.ElapsedMilliseconds)*1000.0/1024.0/1024.0);
                    this.TestContext.WriteLine("Throughput at 100 message size {0:n}", ((double)totalData / (double)watch.ElapsedMilliseconds) * 1000.0 / 100.0);
                    this.TestContext.WriteLine("Throughput at 256 message size {0:n}", ((double)totalData / (double)watch.ElapsedMilliseconds) * 1000.0 / 256.0);
                    this.TestContext.WriteLine("Throughput at 1KB message size {0:n}", ((double)totalData / (double)watch.ElapsedMilliseconds) * 1000.0 / 1024.0);
                }
            );
        }
    }
}
